package net.pulseproject.commons.util;

import java.lang.reflect.Method;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Supports String, Boolean and Integer but no floats or doubles. 
 */
public final class TypeUtil {
	
	private static final Log LOG = LogFactory.getLog(TypeUtil.class);
	
	private TypeUtil() {
		// util classes should not be instantiated
	}
	public static void invokeSetter(final Object host, final String propertyName, final Object propertyValue) {
		if(host == null) { throw new IllegalArgumentException("host == null"); }
		if(propertyName == null) { throw new IllegalArgumentException("propertyName == null"); }
		if(propertyName.isEmpty()) { throw new IllegalArgumentException("propertyName is empty"); }
		if(propertyValue == null) { throw new IllegalArgumentException("propertyValue == null"); }
		
		final String setterMethodName = StringUtil.prefixWithSet(propertyName);
		
		try {
			final Method setterMethod = TypeUtil.fetchMethod(host, setterMethodName);
			setterMethod.invoke(host, propertyValue);
		} catch(final Exception e) {
			LOG.warn("Exception while invoking setter! " +
					"(" +
					"propertyValue=" + propertyValue + ", " + 
					"propertyValue.type=" + propertyValue.getClass().getSimpleName() +
					")");
			throw new SetterInvocationException(host, propertyName, propertyValue, setterMethodName, e);
		}
	}

	public static Method fetchMethod(final Object host, final String methodName) {
		for (final Method currentMethod : host.getClass().getMethods()) {
			if(currentMethod.getName().equals(methodName) == true) {
				return currentMethod;
			}
		}
		throw new RuntimeException("Could not find method by name [" + methodName + "] for object: " + host);
	}
	
	public static Object castString(final String rawString) {
		if(rawString == null) { throw new IllegalArgumentException("rawString == null"); }
		
		if(rawString.isEmpty() == true) {
			return rawString;
		}
		
		try {
			return Integer.valueOf(Integer.parseInt(rawString));
		} catch(final NumberFormatException e) {
			
			try {
				return Float.valueOf(Float.parseFloat(rawString));
			} catch(final NumberFormatException e2) {
				
				if("true".equalsIgnoreCase(rawString) == true) {
					return Boolean.TRUE;
				}
				
				if("false".equalsIgnoreCase(rawString) == true) {
					return Boolean.FALSE;
				}
				
				return rawString;
			}
		}
	}
	
	public static boolean hasSetterMethod(final Class<?> clazz, final String propertyName) {
		final String setterMethodName = StringUtil.prefixWithSet(propertyName);
		for(final Method method : clazz.getMethods()) {
			if(method.getName().equals(setterMethodName) == true) {
				return true;
			}
		}
		return false;
	}
	
}
